package com.platform.qujia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.platform.qujia.constantEnum.Constant;
import com.platform.qujia.constantEnum.DecimalConstant;
import com.platform.qujia.constantEnum.RedisKey;
import com.platform.qujia.controller.CouponController;
import com.platform.qujia.dao.PayOrderMapper;
import com.platform.qujia.dao.PayWayMapper;
import com.platform.qujia.dao.SaleActivityOrderMapper;
import com.platform.qujia.enums.*;
import com.platform.qujia.param.request.PayInfoRequest;
import com.platform.qujia.pay.strategy.YunhuaChannel;
import com.platform.qujia.pojo.*;
import com.platform.qujia.pojo.dto.DivideAccountsSettingDto;
import com.platform.qujia.pojo.req.SaleActivityOrderCreateReq;
import com.platform.qujia.service.*;
import com.platform.qujia.utils.*;
import com.platform.qujia.utils.exception.CustomException;
import com.platform.qujia.utils.sxfpay.SXFPayParam;
import com.platform.qujia.utils.sxfpay.SXFPayUtil;
import com.platform.qujia.utils.weixinapp.WxPushUtil;
import com.platform.qujia.utils.yunHua.YunHuaParam;
import com.platform.qujia.utils.yunHua.yunHuaPayUtils;
import com.yunhua.oil.common.core.utils.LocalDateUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @date 2023/12/24
 */
@Service
public class SaleActivityOrderServiceImpl extends ServiceImpl<SaleActivityOrderMapper, SaleActivityOrder> implements ISaleActivityOrderService {

    private static final Logger log = LoggerFactory.getLogger(SaleActivityOrderServiceImpl.class);

    @Autowired
    private ISaleActivityService saleActivityService;
    @Resource
    private PayOrderMapper payOrderMapper;
    @Autowired
    private AppUserInfoService appUserInfoService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private CouponController couponController;
    @Autowired
    private ISaleActivityCouponRelService saleActivityCouponRelService;
    @Autowired
    private GzhNewsTemplateService gzhNewsTemplateService;
    @Autowired
    private EnterpriseService enterpriseService;
    @Autowired
    private PayWayMapper payWayMapper;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private WxPushUtil wxPushUtil;
    @Value("${domain.payName}${server.servlet.context-path}")
    private String baseUrl;
    @Value("${qujia.yunhuaPrePayUrl}")
    private String yunHuaPrePayUrl;
    @Value("${qujia.yunhuaPayUrl}")
    private String yunhuaPayUrl;

    @Override
    public SaleActivityOrder createOder(SaleActivityOrderCreateReq orderCreateReq) {
        Long saleActivityId = orderCreateReq.getSaleActivityId();
        Integer purchaseNum = orderCreateReq.getPurchaseNum();
        SaleActivity activity = saleActivityService.getById(saleActivityId);
        Assert.isTrue(activity != null && activity.getActivityEnable() == 1,"活动不存在");
        LocalDateTime now = LocalDateTime.now();
        if (activity.getStartTime().isAfter(now) || activity.getEndTime().isBefore(now)) {
            throw new CustomException("不在活动期间");
        }
        if (activity.getStock() < purchaseNum) {
            throw new CustomException("库存不足");
        }
        BigDecimal reqAmt = new BigDecimal(orderCreateReq.getAmt());
        BigDecimal orderAmt = activity.getPrice().multiply(BigDecimal.valueOf(purchaseNum)).setScale(2,RoundingMode.HALF_UP);
        if (orderAmt.compareTo(reqAmt) != 0 ) {
            throw new CustomException("活动信息已过期");
        }
        AppUserInfo userInfo = appUserInfoService.getById(orderCreateReq.getUserId());
        if (userInfo == null ||
                userInfo.getStationId() != activity.getEnterpriseId().intValue() ||
                !StringUtils.equals(userInfo.getMobilePhone(),orderCreateReq.getMobilePhone())) {
            throw new CustomException("用户不存在");
        }
        if (activity.getMaxBuyNum() > 0) {
//            if (orderCreateReq.getPurchaseNum() > activity.getMaxBuyNum()) {
//                throw new CustomException("超过最大购买数量");
//            }
//            Integer boughtNum = baseMapper.queryUserBoughtNum(saleActivityId, userInfo.getUserId(),OrderStatus.PAID);
//            if (MathUtil.add(boughtNum, orderCreateReq.getPurchaseNum()) > activity.getMaxBuyNum()) {
//                throw new CustomException("超过最大购买数量");
//            }
            Integer boughtCount = baseMapper.queryUserBoughtCount(saleActivityId, userInfo.getUserId(),OrderStatus.PAID);
            if (MathUtil.add(boughtCount, 1) > activity.getMaxBuyNum()) {
                throw new CustomException("超过最大购买次数");
            }
        }
        String ordNo = com.platform.qujia.utils.StringUtils.generateOrdNo();
        SaleActivityOrder activityOrder = new SaleActivityOrder();
        activityOrder.setOrderNo(ordNo);
        activityOrder.setSaleActivityId(activity.getId());
        activityOrder.setSaleActivityName(activity.getActivityName());
        activityOrder.setEnterpriseId(activity.getEnterpriseId());
        activityOrder.setCustomerId(userInfo.getUserId());
        activityOrder.setCustomerName(userInfo.getBlogNickName());
        activityOrder.setMobilePhone(userInfo.getMobilePhone());
        activityOrder.setPurchaseNum(purchaseNum);
        activityOrder.setAmt(orderAmt);
        activityOrder.setPayType("wx");
        activityOrder.setCreateTime(now);
        activityOrder.setOrderStatus(OrderStatus.NOT_PAY);
        activityOrder.setShipmentStatus(ShipmentStatus.NOT_SHIP);
        transactionTemplate.executeWithoutResult(transactionStatus -> {
            int i = saleActivityService.increaseStock(saleActivityId, -purchaseNum);
            if (i == 0) {
                throw new CustomException("库存不足");
            }
            this.save(activityOrder);
        });
        Long createTime = LocalDateTimeUtil.parseMillisecond(activityOrder.getCreateTime());
        redisTemplate.opsForZSet().add(RedisKey.SALE_ACTIVITY_ORDER_NOT_PAY,activityOrder.getOrderNo(),createTime);
        return activityOrder;
    }

    @Override
    public Map<String, Object> toThirdPay(PayInfoRequest payInfoRequest) {
        log.info("秒杀拉起支付，参数:{}",payInfoRequest);
        if (StringUtils.isBlank(payInfoRequest.getStationId()) || StringUtils.isBlank(payInfoRequest.getOrdNo())) {
            throw new CustomException("缺少必传参数");
        }
        if (StringUtils.isBlank(payInfoRequest.getOpenId()) && StringUtils.isBlank(payInfoRequest.getAliUserId())) {
            throw new CustomException("缺少用户参数");
        }
        SaleActivityOrder form = new SaleActivityOrder();
        form.setOrderNo(payInfoRequest.getOrdNo());
        SaleActivityOrder activityOrder = getOne(new QueryWrapper<>(form));
        if (activityOrder == null) {
            log.error("订单号未找到,orderNo:[{}]",payInfoRequest.getOrdNo());
            throw new CustomException("订单未找到");
        }
        if (activityOrder.getOrderStatus() != OrderStatus.NOT_PAY) {
            log.error("订单状态不对,orderNo:[{}],status:[{}]",payInfoRequest.getOrdNo(),activityOrder.getOrderStatus());
            throw new CustomException("订单状态不对");
        }
        Station station = enterpriseService.selectStationById(Integer.valueOf(payInfoRequest.getStationId()));
        if (station == null) {
            throw new CustomException("油站未找到");
        }
        PayWay pf = new PayWay();
        pf.setStationId(Integer.valueOf(payInfoRequest.getStationId()));
        pf.setUseType(PayWayUseTypeEnum.CONSUME.getValue().toString());
        pf.setAppType(AppTypeEnum.WX.getValue());
        PayWay payWay = payWayMapper.getOneStationPayWay(pf);
        if (payWay == null || payWay.getServiceCharge() == null) {
            throw new CustomException("支付渠道未找到");
        }
        AppUserInfo appUserInfo = appUserInfoService.getById(activityOrder.getCustomerId());
        String userId = YunhuaChannel.DEFAULT_USER_ID;
        if (appUserInfo != null) {
            if (StringUtils.isNotBlank(appUserInfo.getYunhuaUserId())) {
                userId = appUserInfo.getYunhuaUserId();
            } else if (!MobilePhoneUtil.isFakePhone(appUserInfo.getMobilePhone())) {
                userId = appUserInfo.getMobilePhone();
            }
        }
        SaleActivityOrder update = new SaleActivityOrder();
        update.setId(activityOrder.getId());
        update.setPayWayId(Long.valueOf(payWay.getPayWayId()));
        update.setEnterpriseName(station.getEnterprise().getEnterpriseName());
        update.setStationId(Long.valueOf(station.getStationId()));
        update.setStationName(station.getStationName());
        calculateAndSetChannelFee(update,activityOrder.getAmt(),payWay);
        updateById(update);
        if (update.getAmt() != null) {
            activityOrder.setAmt(update.getAmt());
        }
        String payType = activityOrder.getPayType();
        String payTypeSta = payWay.getPayType();     //第三方支付类型
        String mno = payWay.getMno();                //商户号
        String weChatType = "2";
        if (payInfoRequest.getPayAppType() != null && !"".equals(payInfoRequest.getPayAppType()) && "1".equals(payInfoRequest.getPayAppType())) {
            weChatType = "1";
        }
        BigDecimal amt = activityOrder.getAmt();
        String amtStr = activityOrder.getAmt().toString();
        String ordNo = activityOrder.getOrderNo();
        String payType_num = "";
        String openId = "";
        switch (activityOrder.getPayType()) {
            case "wx":   //微信
                payType_num = "1";
                openId = payInfoRequest.getOpenId();
                break;
            case "zfb":  //支付宝
                payType_num = "2";
                openId = payInfoRequest.getAliUserId();
                break;
//            case "yl":   //银联
//                payType_num = "3";
//                break;
        }
        String subject = "秒杀活动-"+StringUtils.abbreviate(activityOrder.getSaleActivityName(),8);
        String notifyUrl = null;
        Map<String,Object> resultMap = new HashMap<>();
        try{
            switch (payTypeSta) {
                case "1":   //随行付
                    notifyUrl = baseUrl + "/saleActivityOrder/callback/sxf";

                    String ledgerAccountFlag = "0";

                    resultMap = SXFPayUtil.sxfGoPay(
                            SXFPayParam.builder()
                                    .amt(amtStr)
                                    .appId(null)
                                    .mno(mno)
                                    .ordNo(ordNo)
                                    .notifyUrl(notifyUrl)
                                    .subject(subject)
                                    .userId(openId)
                                    .ledgerAccountFlag(ledgerAccountFlag)
                                    .customerIp(payInfoRequest.getCustomerIp())
                                    .ylTrmNo(payInfoRequest.getYlTrmNo())
                                    .userType(payType_num)
                                    .weChatType(weChatType)
                                    .build());
                    break;
                case "5":   //云华支付
                    notifyUrl = baseUrl + "/saleActivityOrder/callback/yh";
                    log.info("weChatType{}", weChatType);
                    switch (payType) {
                        case "zfb":
                            log.info("支付宝拉起支付");
                            resultMap = yunHuaPayUtils.yunHuaPayAli(YunHuaParam.builder()
                                    .partnerCode(mno)
                                    .posOrderNo(ordNo)
                                    .openId(openId)
                                    .noticeUrl(notifyUrl)
                                    .txnDesc(subject)
                                    .miniUrl("www.123.com")
                                    .txnAmt(amt)
                                    .userId(userId)
                                    .build(), payWay.getSecretKey(), yunhuaPayUrl);
//                            update.setTransNo(resultMap.get("transInfoNo").toString());
//                            update.setPayNo(resultMap.get("transPayNo").toString());
                            break;
                        case "wx":
                            if (weChatType.equals("1")) {
                                //小程序
                                log.info("小程序拉起支付");
                                resultMap = yunHuaPayUtils.yunHuaPayWxMini(YunHuaParam.builder()
                                        .partnerCode(mno)
                                        .posOrderNo(ordNo)
                                        .noticeUrl(notifyUrl)
                                        .miniUrl("www.123.com")
                                        .txnAmt(amt)
                                        .userId(userId)
                                        .build(), payWay.getSecretKey(), yunHuaPrePayUrl);
//                                update.setTransNo(resultMap.get("transInfoNo").toString());
//                                update.setPayNo(resultMap.get("transPayNo").toString());
                            } else {
                                log.info("公众号拉起支付");
                                resultMap = yunHuaPayUtils.yunHuaPayV2(YunHuaParam.builder()
                                        .partnerCode(mno)
                                        .posOrderNo(ordNo)
                                        .noticeUrl(notifyUrl)
                                        .txnDesc(subject)
                                        .txnAmt(amt)
                                        .userId(userId)
                                        .build(), payWay.getSecretKey(), yunHuaPrePayUrl);
//                                update.setTransNo(resultMap.get("transInfoNo").toString());
//                                update.setPayNo(resultMap.get("transPayNo").toString());
                            }
                    }
                    //resultMap.put("payAppId", payAppId);
                    break;
            }
            resultMap.put("thirdPayment", payTypeSta);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CustomException("拉起支付失败");
        }
        return resultMap;
    }

    @Override
    public String callbackSxf(Map<String, Object> request) {
        log.info("=====随行付秒杀回调--参数:{}",request);
//        String sign = (String) request.remove("sign");
//        String signContent = RSASignature.getOrderContent(request);
//        if (!RSASignature.doCheck(signContent, sign, SXFPaySign.sxfPublic)) {
//            log.info("=====随行付回调验签失败--参数:{}",request);
//            return SxfCallbackServiceImpl.FAIL_RETURN_VALUE;
//        }
        String ordNo = String.valueOf(request.get("ordNo"));
        if (StringUtils.isBlank(ordNo)) {
            log.info("=====订单号为空");
            return SxfCallbackServiceImpl.SUCCESS_RETURN_VALUE;
        }
        String payTimeStr = String.valueOf(request.get("payTime"));
        LocalDateTime payTime;
        if (StringUtils.isNotBlank(payTimeStr)) {
            try{
                payTime = LocalDateUtils.parseLocalDateTime(payTimeStr,LocalDateTimeUtil.YYYYMMDDHHMMSS);
            }catch (Exception ex){
                log.error(ex.getMessage(),ex);
                payTime = LocalDateTime.now();
            }
        }else{
            payTime = LocalDateTime.now();
        }
        orderCallback(null,ordNo,payTime,false);
        return SxfCallbackServiceImpl.SUCCESS_RETURN_VALUE;
    }

    @Override
    public String callbackYh(Map<String, Object> request) {
        log.info("=====云化秒杀回调--参数:{}",request);
        String ordNo = (String) request.get("clientSerialNo");
        if (StringUtils.isBlank(ordNo)) {
            log.info("=====订单号为空");
            return YunhuaChannel.SUCCESS_RETURN_VALUE;
        }
        String status = String.valueOf(request.get("status"));
        if (!StringUtils.equals("3", status)) {
            log.info("=====云化秒杀回调--状态不对,ordNo:{},status:{}",ordNo,status);
            return YunhuaChannel.SUCCESS_RETURN_VALUE;
        }
        String payTimeStr = String.valueOf(request.get("payTime"));
        LocalDateTime payTime;
        if (StringUtils.isNotBlank(payTimeStr)) {
            try{
                payTime = LocalDateTime.parse(payTimeStr);
            }catch (Exception ex){
                log.error(ex.getMessage(),ex);
                payTime = LocalDateTime.now();
            }
        }else{
            payTime = LocalDateTime.now();
        }
        orderCallback(request,ordNo,payTime,true);
        return YunhuaChannel.SUCCESS_RETURN_VALUE;
    }

    @Override
    public void cancelOrder(String orderNo) {
        log.info("取消过期订单:[{}]",orderNo);
        SaleActivityOrder form = new SaleActivityOrder();
        form.setOrderNo(orderNo);
        SaleActivityOrder activityOrder = getOne(new QueryWrapper<>(form));
        if (activityOrder == null) {
            log.error("订单号未找到,orderNo:[{}]",orderNo);
            return;
        }
        if (activityOrder.getOrderStatus() != OrderStatus.NOT_PAY) {
            log.error("订单状态不对,orderNo:[{}],status:[{}]",orderNo,activityOrder.getOrderStatus());
            return;
        }
        SaleActivityOrder update = new SaleActivityOrder();
        update.setOrderStatus(OrderStatus.PAY_FAIL);
        LambdaQueryWrapper<SaleActivityOrder> qw = Wrappers.lambdaQuery(SaleActivityOrder.class);
        qw.eq(SaleActivityOrder::getOrderStatus,OrderStatus.NOT_PAY).eq(SaleActivityOrder::getId,activityOrder.getId());
        transactionTemplate.executeWithoutResult(transactionStatus -> {
            boolean b = update(update, qw);
            if (b) {
                saleActivityService.increaseStock(activityOrder.getSaleActivityId(),activityOrder.getPurchaseNum());
                return;
            }
            log.info("定时取消更新订单，订单状态不对，更新失败");
        });

    }

    @Override
    public List<SaleActivityOrder> queryList(Long enterpriseId, Integer userId, String mobilePhone) {
        SaleActivityOrder form = new SaleActivityOrder();
        form.setEnterpriseId(enterpriseId);
        form.setCustomerId(userId);
        LambdaQueryWrapper<SaleActivityOrder> qw = new LambdaQueryWrapper<>(form);
        qw.eq(SaleActivityOrder::getOrderStatus,OrderStatus.PAID).orderByDesc(SaleActivityOrder::getId);
        return list(qw);
    }

    private void orderCallback(Map<String, Object> request,String orderNo,LocalDateTime payTime,boolean yh){
        SaleActivityOrder form = new SaleActivityOrder();
        form.setOrderNo(orderNo);
        SaleActivityOrder activityOrder = getOne(new QueryWrapper<>(form));
        if (activityOrder == null) {
            log.error("订单号未找到,orderNo:[{}]",orderNo);
            return;
        }
        if (yh) {
            sendSettleInfo(request,activityOrder);
        }
        if (activityOrder.getOrderStatus() != OrderStatus.NOT_PAY && activityOrder.getOrderStatus() != OrderStatus.PAY_FAIL) {
            log.error("订单状态不对,orderNo:[{}],status:[{}]",orderNo,activityOrder.getOrderStatus());
            return;
        }
        SaleActivityOrder update = new SaleActivityOrder();
        update.setOrderStatus(OrderStatus.PAID);
        update.setPayTime(payTime);
        update.setShipmentStatus(ShipmentStatus.SHIPPED);
        if (yh) {
            update.setTransNo(String.valueOf(request.get("transInfoNo")));
            update.setPayNo(String.valueOf(request.get("transPayNo")));
        }
        LambdaQueryWrapper<SaleActivityOrder> qw = Wrappers.lambdaQuery(SaleActivityOrder.class);
        qw.eq(SaleActivityOrder::getOrderStatus,OrderStatus.NOT_PAY).eq(SaleActivityOrder::getId,activityOrder.getId());
        Boolean execute = transactionTemplate.execute(transactionStatus -> {
            boolean b = update(update, qw);
            if (!b) {
                log.info("回调更新订单，订单状态不对，更新失败,ordNo:[{}]",activityOrder.getOrderNo());
                update.setShipmentStatus(ShipmentStatus.SHIP_FAIL);
                update.setId(activityOrder.getId());
                updateById(update);
                return false;
            }
            return true;
        });
        if (execute == null || Boolean.FALSE.equals(execute)) {
            log.info("更新失败");
            // todo
            return;
        }
        redisTemplate.opsForZSet().remove(RedisKey.SALE_ACTIVITY_ORDER_NOT_PAY, orderNo);
        SaleActivityCouponRel couForm = new SaleActivityCouponRel();
        couForm.setSaleActivityId(activityOrder.getSaleActivityId());
        List<SaleActivityCouponRel> list = saleActivityCouponRelService.list(Wrappers.query(couForm));
        List<String> couponIds = list.stream().map(SaleActivityCouponRel::getCouponId).collect(Collectors.toList());
        if (!couponIds.isEmpty()) {
            try{
                couponController.drawCouponsForSaleActivity(activityOrder.getMobilePhone(), couponIds, Constant.COUPON_USER_BIZ_TYPE_SALE_ACTIVITY,activityOrder.getId(),8,activityOrder.getPurchaseNum());
            } catch (Exception e) {
                log.error("秒杀发卷异常");
                log.error(e.getMessage(), e);
            }
        }
        activityOrder.setPayTime(payTime);
        activityOrder.setOrderStatus(OrderStatus.PAID);
        gzhNewsTemplateService.saleOrderPush(activityOrder);
        if (!couponIds.isEmpty()) {
            AppUserInfo userInfo = appUserInfoService.getById(activityOrder.getCustomerId());
            if (userInfo != null && StringUtils.isNotBlank(userInfo.getBlogOpenid())) {
                Map<String, String> templateParams = new HashMap<>();
                templateParams.put("openid", userInfo.getBlogOpenid());
                templateParams.put("stationName", activityOrder.getStationName());
                templateParams.put("couponContent", String.format("恭喜获得%d张优惠劵",couponIds.size()*activityOrder.getPurchaseNum()));
                wxPushUtil.sendTemplateMsg(Math.toIntExact(activityOrder.getEnterpriseId()),templateParams, WxTemplateEnum.COUPON_DISTRIBUTION);
            }
        }
    }

    private void calculateAndSetChannelFee(SaleActivityOrder activityOrder,BigDecimal amt,PayWay payWay){
        if (payWay == null || payWay.getServiceCharge() == null) {
            activityOrder.setServiceCharge(BigDecimal.ZERO);
            return;
        }
        if(amt.compareTo(DecimalConstant.O_01)<=0){
            activityOrder.setServiceCharge(BigDecimal.ZERO);
            return;
        }
        BigDecimal serviceCharge = payWay.getServiceCharge();
        if (StringUtils.equals("1",payWay.getChannelFeePayer())) {
            // 油企承担
            //渠道费
            BigDecimal commission = amt.multiply(serviceCharge).multiply(DecimalConstant.O_001).setScale(2, RoundingMode.HALF_UP);
            activityOrder.setServiceCharge(commission);
        }else{
            // 司机承担
            // 司机承担的渠道费
            BigDecimal driverCommission = amt.multiply(serviceCharge).multiply(DecimalConstant.O_001).setScale(2, RoundingMode.HALF_UP);
            amt = amt.add(driverCommission).setScale(2,RoundingMode.HALF_UP);
            activityOrder.setAmt(amt);
            activityOrder.setServiceCharge(amt.multiply(serviceCharge).multiply(DecimalConstant.O_001).setScale(2,RoundingMode.HALF_UP));
        }
    }

    private void sendSettleInfo(Map<String, Object> request,SaleActivityOrder activityOrder){
        PhysicalCardBalance pcb = new PhysicalCardBalance();
        pcb.setStationId(String.valueOf(activityOrder.getStationId()));
        pcb.setPayWayId(activityOrder.getPayWayId());
        pcb.setAmount(activityOrder.getAmt());
        pcb.setBalanceNo(activityOrder.getOrderNo());
        gzhNewsTemplateService.sendStkSettleInfo(pcb,request);
    }
}
